Skip to main content

chroot — Creating a Jailed FTP-Only User

Learning Focus

By the end of this lesson, you will be able to lock a specific user into a restricted directory using vsftpd and chroot, preventing them from accessing the wider filesystem or logging in via SSH.

Overview

A chroot "jail" isolates a user by changing the apparent root directory for that user's session. In this context, rather than using the complex standalone chroot command for a full shell environment, we use the built-in chroot functionality of an FTP server (vsftpd) to safely confine a user (e.g., a designer editing WordPress themes) to a specific directory.

Capability Snapshot
  • Core Function: Isolate user to a specific directory (chroot).
  • Primary Benefit: Restricts access to sensitive system files and prevents SSH shell access.
  • Where to Use: Giving third-party developers, designers, or content editors limited access to a site root or specific folder.
  • Workflow: Install vsftpd -> Set nologin shell -> Configure vsftpd.conf -> Test FTP access.

Syntax & Configuration Rules

Unlike single commands, securing an FTP user involves modifying system files and configuration directives:

Key vsftpd Directives

DirectiveDescriptionExample Target⭐ Rating
::::
local_enable=YESAllow local system users to log inYES⭐⭐⭐⭐⭐
chroot_local_user=YESJail users inside their assigned local rootYES⭐⭐⭐⭐⭐
allow_writeable_chroot=YESPrevent "500 OOPS: chroot" errors when root is writableYES⭐⭐⭐⭐⭐
local_root=/pathAuto-assign root directory for the user/home/$USER/public_html⭐⭐⭐⭐
user_sub_token=$USERAllow dynamic user variables in config$USER⭐⭐⭐

Shell Access Control

File/SettingDescriptionAction
:::
/usr/sbin/nologinPrevents the user from opening an SSH shell.Assign as user's shell in /etc/passwd.

Step-by-Step Examples

This section walks through the process of jailing a designer to a WordPress theme directory.

Environment Preparation

Assume your WordPress site root is /home/wpstrategist/public_html/. We want to jail the designer to /home/wpstrategist/public_html/wp-content/themes/.

Install FTP Service (vsftpd)

sudo apt update
sudo apt install vsftpd -y
sudo systemctl enable --now vsftpd

Configure vsftpd for Chroot

Backup the default configuration and create a secure one:

sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.backup
sudo nano /etc/vsftpd.conf

Minimal working secure configuration:

# Basic Settings
listen=YES
listen_ipv6=NO
anonymous_enable=NO
local_enable=YES
write_enable=YES
chroot_local_user=YES

# Security Jailing
allow_writeable_chroot=YES
user_sub_token=$USER
local_root=/home/$USER/public_html
pam_service_name=vsftpd
ssl_enable=NO # Set to YES in production for TLS

# Logging
xferlog_enable=YES
xferlog_std_format=YES

Restart the service:

sudo systemctl restart vsftpd

Create the Restricted User

Create a user without SSH access by setting their shell to nologin:

sudo adduser designer --home /home/designer --shell /usr/sbin/nologin

Verify the restriction:

grep designer /etc/passwd
# Expected output ends in /usr/sbin/nologin

Create the folder structure and symlink the actual theme directory so edits instantly reflect on the site:

sudo mkdir -p /home/designer/public_html/wp-content/themes
sudo chown -R designer:designer /home/designer
sudo chmod -R 755 /home/designer
sudo ln -s /home/wpstrategist/public_html/wp-content/themes /home/designer/public_html/wp-content/themes

Apply Selective Chroot (Optional)

If you only want specific users jailed (instead of all local users):

# In /etc/vsftpd.conf:
chroot_local_user=NO
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list

Add the user to the list:

echo "designer" | sudo tee -a /etc/vsftpd.chroot_list
sudo systemctl restart vsftpd

Practical Use Cases

WordPress Theme Designer

Limit a designer to only the wp-content/themes directory using an FTP client like FileZilla or Cyberduck. They cannot access system configuration or other users' sites.

Shared Hosting Environment

Confine multiple clients to their respective /var/www/domain.com directories without giving them access to the root filesystem or each other's files.

Log Reviewer

Create a read-only FTP user jailed to /var/log for external auditors or log parsing tools.

Common Mistakes & Troubleshooting

ProblemCauseFix
:::
500 OOPS: vsftpd: refusing to run with writable root inside chroot()The chroot jail directory is fully writable.Set allow_writeable_chroot=YES in vsftpd.conf.
Login fails with "530 Login incorrect"Wrong password, or shell is blocked by PAM.Ensure /usr/sbin/nologin is listed in /etc/shells.
Connects successfully but shows an empty folderIncorrect local_root variable mapping.Check local_root=/home/$USER/public_html.
The user can still connect via SSHShell is set to bash instead of nologin.Run sudo usermod -s /usr/sbin/nologin designer.
Permission denied on uploadThe user doesn't own the destination directory.Run sudo chown -R designer:designer /home/designer.

Best Practices

  • Enforce TLS: Always configure ssl_enable=YES in vsftpd.conf for production environments to prevent plaintext password sniffing.
  • Use nologin over false: Setting the shell to /usr/sbin/nologin provides a clean rejection message for SSH attempts.
  • Minimize Shared Dependencies: If using a manual system chroot instead of built-in FTP jailing, copy only required libraries into the jail path.
  • Audit Logs: Monitor /var/log/vsftpd.log or xferlog to track exactly what the restricted user uploads or manipulates.

Hands-On Practice

Task: Create a Jailed Contributor

  1. Install vsftpd and configure it to lock local users into their homes with chroot_local_user=YES.
  2. Create a user named contractor with /usr/sbin/nologin as their shell.
  3. Establish a directory path /home/contractor/data_drop and give them write access.
  4. Challenge: Try to log in as contractor via ssh. Observe the rejection. Then log in via an FTP client and attempt to access /etc. Verify that you are trapped in the /home/contractor directory.

Connection to Other Concepts

  • Groups and Permissions: Use Linux groups alongside chroot to manage teams of jailed users efficiently.
  • OpenSSH ChrootDirectory: For an SFTP alternative that doesn't require a separate FTP server, SSH can be configured to jail users securely using ChrootDirectory.

Visual Learning Diagram

Command Execution Examples

Here are 10 practical command examples with expected inputs and outputs related to managing a chrooted FTP user.

Install FTP Service

sudo apt install vsftpd

Expected output:

Reading package lists... Done
Building dependency tree...
Setting up vsftpd (3.0.5-0ubuntu1) ...

Explanation: Installs the vsftpd (Very Secure FTP Daemon) package on Ubuntu/Debian systems.

Check FTP Service Status

sudo systemctl status vsftpd

Expected output:

● vsftpd.service - vsftpd FTP server
Loaded: loaded (/lib/systemd/system/vsftpd.service; enabled)
Active: active (running)

Explanation: Verifies that the vsftpd service is actively running and enabled to start on system boot.

Create a User with No Shell

sudo adduser designer --shell /usr/sbin/nologin

Expected output:

Adding user `designer' ...
Adding new group `designer' (1001) ...
Adding new user `designer' (1001) ...
Creating home directory `/home/designer' ...

Explanation: Creates a new user named designer whose shell is restricted, preventing terminal/SSH logins.

Verify User Shell Restriction

grep designer /etc/passwd

Expected output:

designer:x:1001:1001:,,,:/home/designer:/usr/sbin/nologin

Explanation: Confirms that the user's shell is properly set to /usr/sbin/nologin in the system's password file.

Create the Jailed Directory

sudo mkdir -p /home/designer/public_html

Expected output: (No output) Explanation: Creates the public_html directory inside the user's home where they will be jailed and can upload files.

Assign Directory Ownership

sudo chown -R designer:designer /home/designer

Expected output: (No output) Explanation: Recursively grants the designer user ownership of their home directory, allowing them to read and write files.

Enable Chroot in vsftpd.conf

echo "chroot_local_user=YES" | sudo tee -a /etc/vsftpd.conf

Expected output:

chroot_local_user=YES

Explanation: Appends the chroot_local_user directive to the configuration file, enforcing the jail for all local users.

Restart FTP Service

sudo systemctl restart vsftpd

Expected output: (No output) Explanation: Restarts the vsftpd daemon to apply the new configuration changes.

Test SSH Rejection

ssh designer@localhost

Expected output:

designer@localhost's password:
This account is currently not available.
Connection to localhost closed.

Explanation: Proves that the user is securely blocked from accessing an SSH shell.

Audit FTP Activity Logs

sudo tail /var/log/vsftpd.log

Expected output:

Mon Oct 23 10:15:00 2023 [pid 1234] [designer] OK LOGIN: Client "192.168.1.100"
Mon Oct 23 10:15:05 2023 [pid 1234] [designer] OK UPLOAD: Client "192.168.1.100", "/home/designer/public_html/style.css", 1024 bytes

Explanation: Displays the last few lines of the FTP transfer log, showing successful logins and file uploads by the jailed user.

What's Next: Proceed to explore sudo Configuration to understand the opposite of restriction: delegating root privileges safely.